package edu.uta.cfl.console;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

import edu.uta.cfl.GUI.BEN;
import edu.uta.cfl.data.Combo;
import edu.uta.cfl.data.IterationResult;
import edu.uta.cfl.data.SUT;
import edu.uta.cfl.data.SUT.SUTState;
import edu.uta.cfl.engine.ComboManager;
import edu.uta.cfl.engine.IterationOutput;
import edu.uta.cfl.engine.SUTInfoReader;
import edu.uta.cfl.engine.SUTInfoWriter;
import edu.uta.cfl.engine.SUTManager;
import edu.uta.cfl.engine.UpdateTestSet;
import edu.uta.cfl.util.Constants;
import edu.uta.cfl.util.Util;

public class CFLEngine {

	private static CFLEngine instance;
	public static SUT sut;
	/**
	 * @return the sut
	 */
	public static SUT getSut() {
		return sut;
	}

	public static int curCmbLen;
	public static int itrCount = 0;
	public static IterationResult iteration2;
	public static int itr;

	public static CFLEngine getInstance()
	{
		if(instance == null)
		{
			instance = new CFLEngine();
		}
		return instance;
	}
	

	public static void processLoad(String input) {
		sut = new SUT();
		IterationResult iteration1 = new IterationResult(); 
		sut = (new SUTInfoReader(input)).getSUT();
		curCmbLen = sut.getStrength();
		SUTManager.approach(sut, sut.getStrength(), Constants.APPROACH_LOAD);

		// approachState = Constants.APPROACH_ADD;
		ArrayList<int[]> tcList = new ArrayList<int[]>();

		if (sut.getStatus() == SUTState.expansion) {
			sut.setStatus(SUTState.expansion);
			int len = curCmbLen;
			while ((sut.getStatus() == SUTState.expansion)
					&& len < Constants.maxIndStr - 1)
				SUTManager.expandCmb(sut, len++);

			curCmbLen = len;

			if (len < Constants.maxIndStr - 1)
				tcList = SUTManager.generateNewTC(sut, curCmbLen);
			else
				sut.setStatus(SUTState.notFound);

			itr = 0;
		} else
			tcList = SUTManager.generateNewTC(sut, sut.getStrength());
	
		if (sut.getStatus() == SUTState.continuing) {
			// new logic start
			int len = sut.getStrength();
			iteration1.setTestSet(tcList);
			iteration1.setSuspiciousCombos(sut.getSuspiciousCombos(curCmbLen));
			iteration1.setSuspiciousComponents(sut.getSuspiciousComponents(curCmbLen));
			itrCount++;
			System.out.println("Iteration Count:  "+itrCount+"testing arraylist size: "+sut.getIterationObject().size());
			sut.getIterationObject().add(iteration1);
			System.out.println("*^*^Iteration Count:  "+itrCount+"testing arraylist size: "+sut.getIterationObject().size());
		}
	}

	public static void processAddTest(ArrayList<Integer> result) {
		System.out.println("itrCount in CFLEngine    "+itrCount);
		int level = Collections.max(sut.getTs().getLevelAdded()) + 1;
		
		//(new SUTInfoReader(input)).addTestSet(sut);

		// new logic starts
		System.out.println("Size of Result List:"+result.size());
		IterationResult iteration2 = new IterationResult();
		
		new UpdateTestSet(sut,sut.getIterationObject().get(itrCount-1),result).addTestSet();
		
		// new logic ends

		int tsCnt = 0;
		int passCnt = 0;

		ArrayList<Integer> idxLst = new ArrayList<Integer>();
		for (int i = 0; i < sut.getTs().getMatrix().size(); i++) {
			if (sut.getTs().getLevelAdded().get(i) == level) {
				idxLst.add(i);
			}
		}

		if (idxLst.size() == 0) {
			//Util.showMsg("There is no test case or result in " + input);
			return;
		}

		for (int i : idxLst) {
			if (sut.getTs().getResult().get(i) == sut.getTs().PASS) {
				passCnt++;
			}

		}

		ArrayList<int[]> tcList = new ArrayList<int[]>();

		SUTManager.approach(sut, curCmbLen, Constants.APPROACH_ADD);
		for (Combo cmb : sut.getTestGen4TheseCmb()) {
			int i = ComboManager.isCmbInCmbLst(cmb,
					sut.getSuspiciousCombos(curCmbLen));
			if (i != -1) {
				sut.getSuspiciousCombos(curCmbLen).get(i).setFailInd(true);
				sut.setStatus(SUTState.failureInducing);
			}
		}
		
		if (sut.getStatus() != SUTState.failureInducing) {
			if (curCmbLen < Constants.maxIndStr) {
				if (itr < Constants.itrNum) {
					itr++;

					tcList = SUTManager.generateNewTC(sut, curCmbLen);
					if (passCnt == 0 && sut.getStatus() == SUTState.continuing)
						sut.setStatus(SUTState.noImprovement);

				}
			}

			if (itr == Constants.itrNum
					|| sut.getStatus() == SUTState.expansion) {
				if (curCmbLen < Constants.maxIndStr) {
					sut.setStatus(SUTState.expansion);
					int len = curCmbLen;
					while ((sut.getStatus() == SUTState.expansion))
						SUTManager.expandCmb(sut, len++);

					curCmbLen = len;
					if (len < Constants.maxIndStr)
						tcList = SUTManager.generateNewTC(sut, curCmbLen);
					else
						sut.setStatus(SUTState.InducingTest);

				}
				itr = 0;

			}

		}
		System.out.println("\nTesting SUT status at CFL Engine:"+sut.getStatus());
		if (sut.getStatus() == SUTState.continuing) {
		
			//new logic starts

			iteration2.setTestSet(tcList);
			iteration2.setSuspiciousCombos(sut.getSuspiciousCombos(curCmbLen));
			iteration2.setSuspiciousComponents(sut.getSuspiciousComponents(curCmbLen));
			itrCount++;
			sut.getIterationObject().add(iteration2);
			
			//new logic ends

		} 

		Util.showMsg("\n" + idxLst.size() + " new test cases have been added.");

		//printOutput(sut.getStatus(), outTestset);
		//(new SUTInfoWriter(outSpc.substring(0, outSpc.lastIndexOf("\\") + 1)
			//	+ "cmp" + level + ".txt")).printSuspiciousness(sut, curCmbLen);

	}

	public static void printOutput(SUTState appResult, String fileName) {
		(new SUTInfoWriter()).summarizeOutpou(sut, curCmbLen);

		if (appResult == SUTState.continuing)
			Util.showMsg("\nTo increase the confidence of suspicious combos, it is recommended to execute new test cases in \n"
					+ fileName + ".\n");
		else if (appResult == SUTState.notFound) {
			Util.showMsg("\n"
					+ "All tests fails and all combos are failure-inducing. \n");
			System.exit(0);
		} else if (appResult == SUTState.noImprovement) {
			Util.showMsg("\n" + "Adding tests makes no improvement. \n");
			System.exit(0);
		} else if (appResult == SUTState.InducingTest) {
			Util.showMsg("\nNo inducing combination, failed tests are inducing.");
			Util.showMsg("\nEnd.");
			System.exit(0);
		}

		else {
			Util.showMsg("\nEnd.");
			System.exit(0);
		}
	}



}
